home *** CD-ROM | disk | FTP | other *** search
- {
- Ok, here it is. A freeware 100% pascal phongshading program. No extra units
- are required. Just extract the program, and run it. I wrote it in bp 7, but I
- assume it will work in lower versions as well.A few remarks:
- 1) The 'phong-map' is pretty crappy, so it looks a bit like gouraudshading
- (Trust me, it's not :-).
- 2) Don't tell me it's slow, I know that (My latest routines are 6 times
- faster).
- 3) Feel free to use it anywhere you want, and spread it if you want.
- 4) Comments are appreciated, as long as they are positive :-).
-
- I wrote this version exclusively for this purpose, and removing the need for
- extra units or external files wasn't easy (Look at CreateTorusData, it was a
- real pain in the ...). I might post another program in the future calculate
- phong-maps using the complete phong-model, which looks a zillion times better.
- But don't count on it. Just an idea: You can try to use the texture-map
- routine from gfxfx2 to speed it up. I haven't tried it, but it should be
- possible. Last words: Have fun.
-
- >--->---Cut here--->--->
-
- {Freeware phong-shading routine. Spread it if you want. Credit me if you
- use it. Made by Jeroen Bouwens, The Netherlands.
- Mail me:
-
- e-mail : j.bouwens@tn.ft.hse.nl (Preferred)
- Fido : 2:284/123.3
-
- Greets: Alex,Rob,Martijn,Maarten,Bas,Sean,Richard,Marcel,Jurjen,Michel,
- Sonja,N-Faktor and all the other people I met at Wired (Cool party)}
-
- Uses Crt;{$R- $Q-}
-
- Var Faces : Array [1..320,1..3] Of Integer;
- FNX,FNY,FNZ,Pind,PolyZ : Array [1..320] Of Integer;
- BX,BY,BZ,UT,VT,X,Y,Z,NX,NY,NZ : Array [1..160] of Integer;
- Cosinus,Sinus : Array [0..255] of LongInt;
- Pict,Screen2 : Pointer;
- NumOfVerts,NumOfFaces,EyeDist,VirSeg : Word;
- I,J,G,NumVisible,XT1,YT1,ZT1 : Integer;
- Alpha,Beta,Gamma,K : Byte;
- {Timer variables}Time : Longint ABSOLUTE $0040:$006C;
- T1,Aantal : LongInt;
-
- {------Procedures that are not time-critical (Not used during rotation)------}
-
- Procedure Palette(ColNum,R,G,B:Byte); Assembler;
- Asm Mov dx,$3c8; Mov al,ColNum; Out dx,al; Inc dx; Mov al,R;
- Out dx,al; Mov al,G; Out dx,al; Mov al,B; Out dx,al End;
-
- Procedure CalcVertexNormals;
- {Calculate the average normal vector at each vertex-point}
- Var I,J,NF : Integer;
- RelX1,RelY1,RelZ1,RelX2,RelY2,RelZ2,VL : Real;
- Begin
- {In which face is each point used, and average these face-normals}
- For I:=1 To NumOfVerts Do Begin
- RelX1:=0; RelY1:=0; RelZ1:=0; NF:=0;
- For J:=1 To NumOfFaces Do Begin
- If (Faces[J,1]=I) Or (Faces[J,2]=I) Or (Faces[J,3]=I) Then Begin
- RelX1:=RelX1+FNX[J]; RelY1:=RelY1+FNY[J]; RelZ1:=RelZ1+FNZ[J];
- Inc(NF);
- End;
- End;
- If NF<>0 then Begin
- RelX1:=RelX1/NF; RelY1:=RelY1/NF; RelZ1:=RelZ1/NF;
- VL:=Sqrt(RelX1*RelX1+RelY1*RelY1+RelZ1*RelZ1);
- NX[I]:=Round((RelX1/VL)*120); NY[I]:=Round((RelY1/VL)*120);
- NZ[I]:=Round((RelZ1/VL)*120);
- End;
- End;
- End;{CalcVertexNormals}
-
- Procedure CreateTorusData;
- Var HorAngle,VertAngle,Count : Integer;
- CX,CY,RX1,RY1,RZ1,RX2,RY2,RZ2 : Real;
- Begin
-
- NumOfVerts:=160; NumOfFaces:=320; Count:=1;
- For HorAngle:=0 To 15 Do Begin{Calculate vertex-positions}
- CX:=Cos(HorAngle/2.546479089)*170;
- CY:=Sin(HorAngle/2.546479089)*170;
- For VertAngle:=0 To 9 Do Begin
- X[Count]:=Round(CX+Cos(VertAngle/1.592)*Cos(HorAngle/2.546)*90);
- Y[Count]:=Round(CY+Cos(VertAngle/1.592)*Sin(HorAngle/2.546)*90);
- Z[Count]:=Round(Sin(VertAngle/1.59154931)*90);
- Inc(Count);
- End;
- End;
-
- Count:=1;
- For HorAngle:=0 To 15 Do{Store face-data (Which veticies form which face}
- For VertAngle:=0 To 9 Do Begin
- Faces[Count,3]:=HorAngle*10+VertAngle+1;
- Faces[Count,2]:=HorAngle*10+(VertAngle+1) Mod 10+1;
- Faces[Count,1]:=(HorAngle*10+VertAngle+10) Mod 160+1;
- Inc(Count);
- Faces[Count,3]:=HorAngle*10+(VertAngle+1) Mod 10+1;
- Faces[Count,2]:=(HorAngle*10+(VertAngle+1) Mod 10+10) Mod 160+1;
- Faces[Count,1]:=(HorAngle*10+VertAngle+10) Mod 160+1;
- Inc(Count);
- End;
-
- For Count:=1 To 320 Do Begin{Calculate and store face-normals}
- RX1:=X[Faces[Count,2]]-X[Faces[Count,1]];
- RY1:=Y[Faces[Count,2]]-Y[Faces[Count,1]];
- RZ1:=Z[Faces[Count,2]]-Z[Faces[Count,1]];
- RX2:=X[Faces[Count,3]]-X[Faces[Count,1]];
- RY2:=Y[Faces[Count,3]]-Y[Faces[Count,1]];
- RZ2:=Z[Faces[Count,3]]-Z[Faces[Count,1]];
- FNX[Count]:=Round(RY1*RZ2-RY2*RZ1);
- FNY[Count]:=Round(RZ1*RX2-RZ2*RX1);
- FNZ[Count]:=Round(RX1*RY2-RX2*RY1);
- End;
- End;{CreateTorusData}
-
- Procedure Initialize;
- Begin
-
- Asm Mov ax,$13; Int $10 End;
- GetMem(Screen2,64000);
- VirSeg:=Seg(Screen2^);
-
- CreateTorusData;
- CalcVertexNormals;
-
- For I:=0 To 255 Do Begin
- Cosinus[I]:=Round(Cos(I/40.585707465)*128);
- Sinus[I]:=Round(Sin(I/40.585707465)*128);
- End;
-
- GetMem(Pict,65535);
- {Palette-creation. Skip this one to see the non-lineair colour transition}
- For I:=1 To 63 Do Palette(I,I,10+Round(I/1.4),20+Round(I/1.6));
- {Here, the 'phong-map' as I call it is created. Normally I use a different
- routine for that (Looks WAY better), but that one is too big}
- For I:=0 To 255 Do For J:=0 To 255 Do Begin
- Mem[Seg(Pict^):Ofs(Pict^)+Word(256*I)+J]:=
- Round(Sqr(Sqr(Sin(I/81.487)))*Sqr(Sqr(Sin(J/81.487)))*62)+1;
- {Just to show you how it looks: }
- Mem[$A000:320*Round(I/1.25)+J]:=Mem[Seg(Pict^):Ofs(Pict^)+Word(256*I)+J];
- End;
-
- End;{Initialize}
-
- {----------Procedures that are time-critical (Used during rotation)----------}
- Procedure SwapScreen; Assembler;
- Asm Mov dx,$3DA; @@WaitVBL: In al,dx; and al,8; jz @@WaitVBL; Push ds;
- Lds si,Screen2; Mov ax,$A000; Mov es,ax; Xor di,di; Mov cx,16000;
- db $66; Rep Movsw; Pop ds End;
-
- Procedure Cls(Var Where); Assembler;
- Asm Les di,Where; Mov cx,16000; db $66; Xor ax,ax; db $66; Rep Stosw; End;
-
- Procedure Quicksort(Hi : Integer);
- Procedure Sort(L,R : Integer);
- Var I,J,X,Y : Integer;
- Begin
- I:=L; J:=R; X:=PolyZ[(L+R) Div 2];
- Repeat
- While polyz[i]>x do inc(i); While x>polyz[j] do dec(j);
- If I<=J Then Begin
- Y:=PolyZ[I]; PolyZ[I]:=PolyZ[J]; PolyZ[J]:=Y;
- Y:=Pind[I]; Pind[I]:=Pind[J]; Pind[J]:=Y;
- Inc(I); Dec(J);
- End;
- Until I>J;
- If L<J Then Sort(L,J); If I<R Then Sort(I,R);
- End;
- Begin Sort(1,Hi) End;{QuickSort}
-
- Procedure NewTex(X1,Y1,U1,V1,X2,Y2,U2,V2,X3,Y3,U3,V3:Integer;Texture:Pointer);
- {The actual texture-map routine. Only a little commented :-}
- Var TexOfs : Array [0..320] Of Word;
- SO,Long : Word;
- XL,UL,VL,XR,UR,VR : Array [0..200] Of LongInt;
- DY21,DY31,DY32,DX21,DX31,DX32,DU21,DU31,DU32 : LongInt;
- DV21,DV31,DV32,U,V,I,J,K : LongInt;
- Begin
-
- {Sort for increasing y-coordinates}
- For I:=1 To 2 Do Begin
- If Y3<Y2 Then Begin
- J:=Y3; Y3:=Y2; Y2:=J; J:=X3; X3:=X2; X2:=J;
- J:=U3; U3:=U2; U2:=J; J:=V3; V3:=V2; V2:=J; End;
- If Y2<Y1 Then Begin
- J:=Y1; Y1:=Y2; Y2:=J; J:=X1; X1:=X2; X2:=J;
- J:=U1; U1:=U2; U2:=J; J:=V1; V1:=V2; V2:=J; End;
- If Y3<Y1 Then Begin
- J:=Y1; Y1:=Y3; Y3:=J; J:=X1; X1:=X3; X3:=J;
- J:=U1; U1:=U3; U3:=J; J:=V1; V1:=V3; V3:=J End
- End;
-
- {Exception occurs when there are two top y-coords with the same value}
- If (Y1=Y2) And (X1>X2) Then Begin
- J:=X1; X1:=X2; X2:=J; J:=U1; U1:=U2; U2:=J; J:=V1; V1:=V2; V2:=J End;
-
- {Calculate X,U and V along the edges and store these}
- DY21:=Y2-Y1; DY31:=Y3-Y1; DY32:=Y3-Y2; DX21:=X2-X1; DX31:=X3-X1; DX32:=X3-X2;
- DU21:=U2-U1; DU31:=U3-U1; DU32:=U3-U2; DV21:=V2-V1; DV31:=V3-V1; DV32:=V3-V2;
- XL[0]:=X1; XL[0]:=XL[0]*256; UL[0]:=U1;
- UL[0]:=UL[0]*256; VL[0]:=V1; VL[0]:=VL[0]*256;
- If Y1=Y2 Then Begin
- XR[0]:=X2; XR[0]:=XR[0]*256; UR[0]:=U2; UR[0]:=UR[0]*256;
- VR[0]:=V2; VR[0]:=VR[0]*256 End Else Begin
- XR[0]:=XL[0]; UR[0]:=UL[0]; VR[0]:=VL[0]; End;
- For I:=Y1+1 To Y2 Do Begin
- XL[I-Y1]:=XL[I-Y1-1]+(DX31*256) Div DY31;
- XR[I-Y1]:=XR[I-Y1-1]+(DX21*256) Div DY21;
- UL[I-Y1]:=UL[I-Y1-1]+(DU31*256) Div DY31;
- UR[I-Y1]:=UR[I-Y1-1]+(DU21*256) Div DY21;
- VL[I-Y1]:=VL[I-Y1-1]+(DV31*256) Div DY31;
- VR[I-Y1]:=VR[I-Y1-1]+(DV21*256) Div DY21;
- End;
- For I:=Y2+1 To Y3 Do Begin
- XL[I-Y1]:=XL[I-Y1-1]+(DX31*256) Div DY31;
- XR[I-Y1]:=XR[I-Y1-1]+(DX32*256) Div DY32;
- UL[I-Y1]:=UL[I-Y1-1]+(DU31*256) Div DY31;
- UR[I-Y1]:=UR[I-Y1-1]+(DU32*256) Div DY32;
- VL[I-Y1]:=VL[I-Y1-1]+(DV31*256) Div DY31;
- VR[I-Y1]:=VR[I-Y1-1]+(DV32*256) Div DY32;
- End;
-
- {Calculate texture-offsets for longest horizontal line (at Y=Y2)}
- Long:=Y2-Y1;
- If XL[Long]<XR[Long] Then Begin
- U:=UL[Long]; V:=VL[Long]; SO:=256*(V Shr 8)+(U Shr 8);
- For I:=0 To XR[Long] Shr 8-XL[Long] Shr 8 Do Begin
- TexOfs[I]:=256*(V Shr 8)+(U Shr 8)-SO;
- U:=U+((UR[Long]-UL[Long])*256) Div (XR[Long]-XL[Long]+1);
- V:=V+((VR[Long]-VL[Long])*256) Div (XR[Long]-XL[Long]+1);
- End;
- End Else Begin
- U:=UR[Long]; V:=VR[Long]; SO:=256*(V Shr 8)+(U Shr 8);
- For I:=0 To XL[Long] Shr 8-XR[Long] Shr 8 Do Begin
- TexOfs[I]:=256*(V Shr 8)+(U Shr 8)-SO;
- U:=U+((UL[Long]-UR[Long])*256) Div (XL[Long]-XR[Long]+1);
- V:=V+((VL[Long]-VR[Long])*256) Div (XL[Long]-XR[Long]+1);
- End;
- End;
-
- {Fill polygon (=Read back X,U and V-coordinates from buffer) }
- If XL[Long]<XR[Long] Then
- For I:=0 To Y3-Y1 Do Begin
- SO:=256*(VL[I] Shr 8)+(UL[I] Shr 8);
- For J:=XL[I] Shr 8 To XR[I] Shr 8 Do
- Mem[VirSeg:320*(I+Y1)+J]:=Mem[Seg(Texture^):Ofs(Texture^)+SO+
- TexOfs[J-XL[I] Shr 8]]
- End
- Else
- For I:=0 To Y3-Y1 Do Begin
- SO:=256*(VR[I] Shr 8)+(UR[I] Shr 8);
- For J:=XR[I] Shr 8 To XL[I] Shr 8 Do
- Mem[VirSeg:320*(I+Y1)+J]:=Mem[Seg(Texture^):Ofs(Texture^)+SO+
- TexOfs[J-XR[I] Shr 8]]
- End;
- End;{NewTex}
-
- Procedure Rotate(Var X,Y,Z:Integer;Alpha,Beta,Gamma:Byte);
- Var X2,X3,Y1,Y3,Z1,Z2 : Integer;
- Begin
- Y1:=(Cosinus[Alpha]*Y-Sinus[Alpha]*Z) Div 128;
- Z1:=(Sinus[Alpha]*Y+Cosinus[Alpha]*Z) Div 128;
- X2:=(Cosinus[Beta]*X+Sinus[Beta]*Z1) Div 128;
- Z:=(Cosinus[Beta]*Z1-Sinus[Beta]*X) Div 128;
- X:=(Cosinus[Gamma]*X2-Sinus[Gamma]*Y1) Div 128;
- Y:=(Sinus[Gamma]*X2+Cosinus[Gamma]*Y1) Div 128;
- End;{Rotate}
-
- {--------------------------Main program-------------------------------------}
-
- Begin
-
- Initialize; EyeDist:=150; Alpha:=0; Beta:=0; Gamma:=0;
- Aantal:=0; T1:=Time;
- Repeat
- Cls(Screen2^);
-
- For I:=1 To NumOfVerts do Begin
- {Rotate the vertex-coordinates}
- XT1:=X[I]; YT1:=Y[I]; ZT1:=Z[I];
- Rotate(XT1,YT1,ZT1,Alpha,Beta,Gamma);
- Inc(ZT1,468);
- BX[I]:=160+(XT1*EyeDist) Div ZT1;
- BY[I]:=100+((YT1*EyeDist*83) Div 100) Div ZT1;
- BZ[I]:=ZT1;
- {Rotate vertex normals (Here's where the phong-shading is done}
- XT1:=NX[I]; YT1:=NY[I]; ZT1:=NZ[I];
- Rotate(XT1,YT1,ZT1,Alpha,Beta,Gamma);
- UT[I]:=128+XT1; VT[I]:=128+YT1;
- End;
-
- {Sort the polygons by z-value, so I know in which order to draw them}
- NumVisible:=0;
- For I:=1 to NumOfFaces Do
- If (BX[Faces[I,3]]-BX[Faces[I,1]])*(BY[Faces[I,2]]-BY[Faces[I,1]])-
- (BX[Faces[I,2]]-BX[Faces[I,1]])*(BY[Faces[I,3]]-BY[Faces[I,1]])>0 Then
- Begin
- Inc(NumVisible); Pind[NumVisible]:=I;
- PolyZ[NumVisible]:=BZ[Faces[I,1]]+BZ[Faces[I,2]]+BZ[Faces[I,3]];
- End;
-
- QuickSort(NumVisible);
-
- {Draw the object}
- For I:=1 To NumVisible Do
- NewTex(BX[Faces[Pind[I],1]],BY[Faces[Pind[I],1]],
- UT[Faces[Pind[I],1]],VT[Faces[Pind[I],1]],
- BX[Faces[Pind[I],2]],BY[Faces[Pind[I],2]],
- UT[Faces[Pind[I],2]],VT[Faces[Pind[I],2]],
- BX[Faces[Pind[I],3]],BY[Faces[Pind[I],3]],
- UT[Faces[Pind[I],3]],VT[Faces[Pind[I],3]],Pict);
-
- Alpha:=(Alpha+2)Mod 256;Beta:=(Beta+255)Mod 256;Gamma:=(Gamma+1)Mod 256;
- Inc(Aantal); SwapScreen;
- Until KeyPressed;
-
- T1:=Time-T1; TextMode(LastMode);
- WriteLn(Aantal/(T1/18.2) :1:2,' Frames per second');
- ReadLn; Dispose(Pict);Dispose(Screen2);
- End.
-